<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>智能问答系统</title>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    }

    body {
      background-color: #f8fafc;
      color: #1e293b;
      height: 100vh;
      overflow: hidden;
      display: flex;
      flex-direction: column;
    }

    .container {
      display: flex;
      flex: 1;
      max-height: 100vh;
      overflow: hidden;
    }

    /* 左侧聊天区域 */
    .chat-section {
      flex: 1;
      display: flex;
      flex-direction: column;
      border-right: 1px solid #e2e8f0;
      background-color: #ffffff;
      overflow: hidden;
    }

    .chat-header {
      padding: 18px 24px;
      background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
      color: white;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .chat-header h2 {
      font-weight: 600;
      font-size: 1.25rem;
    }

    .chat-header-info {
      font-size: 0.875rem;
      opacity: 0.9;
    }

    .chat-container {
      flex: 1;
      overflow-y: auto;
      padding: 20px;
      background-color: #f1f5f9;
      display: flex;
      flex-direction: column;
      gap: 16px;
    }

    .message {
      max-width: 80%;
      padding: 16px 20px;
      border-radius: 18px;
      position: relative;
      animation: fadeIn 0.3s ease;
      line-height: 1.6;
    }

    @keyframes fadeIn {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }

    .user-message {
      background-color: #3b82f6;
      color: white;
      align-self: flex-end;
      border-bottom-right-radius: 5px;
    }

    .bot-message {
      background-color: white;
      color: #1e293b;
      align-self: flex-start;
      border-bottom-left-radius: 5px;
      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
    }

    .input-container {
      padding: 16px 24px;
      background-color: white;
      border-top: 1px solid #e2e8f0;
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .input-wrapper {
      display: flex;
      background-color: white;
      border-radius: 12px;
      padding: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
      border: 1px solid #cbd5e1;
    }

    .input-wrapper input {
      flex: 1;
      border: none;
      padding: 12px 16px;
      font-size: 16px;
      outline: none;
      background: transparent;
    }

    .input-wrapper button {
      background-color: #3b82f6;
      color: white;
      border: none;
      width: 46px;
      height: 46px;
      border-radius: 50%;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: background-color 0.2s;
    }

    .input-wrapper button:hover {
      background-color: #2563eb;
    }

    .input-wrapper button:disabled {
      background-color: #94a3b8;
      cursor: not-allowed;
    }

    .typing-indicator {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 10px;
      font-size: 14px;
      color: #64748b;
    }

    .typing-dot {
      width: 8px;
      height: 8px;
      background-color: #94a3b8;
      border-radius: 50%;
      animation: bounce 1.4s infinite ease-in-out both;
    }

    .typing-dot:nth-child(1) { animation-delay: -0.32s; }
    .typing-dot:nth-child(2) { animation-delay: -0.16s; }

    @keyframes bounce {
      0%, 80%, 100% { transform: scale(0); }
      40% { transform: scale(1); }
    }

    .source-info {
      margin-top: 12px;
      padding-top: 12px;
      border-top: 1px dashed #e2e8f0;
      font-size: 13px;
      color: #64748b;
    }

    .source-info i {
      margin-right: 6px;
    }

    /* 右侧检索结果区域 */
    .results-section {
      width: 380px;
      display: flex;
      flex-direction: column;
      background-color: #ffffff;
      overflow: hidden;
      border-left: 1px solid #e2e8f0;
    }

    .results-header {
      padding: 18px 24px;
      background-color: #f8fafc;
      border-bottom: 1px solid #e2e8f0;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .results-header h2 {
      font-size: 1.1rem;
      font-weight: 600;
      color: #1e293b;
    }

    .results-container {
      flex: 1;
      overflow-y: auto;
      padding: 20px;
      background-color: #ffffff;
    }

    .result-card {
      background-color: #f8fafc;
      border-radius: 12px;
      padding: 18px;
      margin-bottom: 16px;
      border: 1px solid #e2e8f0;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
      transition: transform 0.2s, box-shadow 0.2s;
    }

    .result-card:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    }

    .result-title {
      font-weight: 600;
      font-size: 16px;
      color: #1e293b;
      margin-bottom: 10px;
      display: flex;
      align-items: center;
    }

    .result-title i {
      margin-right: 8px;
      color: #3b82f6;
    }

    .result-content {
      font-size: 14px;
      color: #475569;
      line-height: 1.5;
      margin-bottom: 15px;
    }

    .result-scores {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      font-size: 13px;
    }

    .score-badge {
      padding: 4px 10px;
      border-radius: 20px;
      font-weight: 500;
      white-space: nowrap;
    }

    .bm25-score {
      background-color: #dbeafe;
      color: #1d4ed8;
    }

    .dpr-score {
      background-color: #d1fae5;
      color: #047857;
    }

    .hybrid-score {
      background-color: #ede9fe;
      color: #7e22ce;
    }

    .final-score {
      background-color: #ffedd5;
      color: #c2410c;
    }

    .original-score {
      background-color: #e0e7ff;
      color: #4f46e5;
    }

    .position-score {
      background-color: #fee2e2;
      color: #b91c1c;
    }

    .title-score {
      background-color: #dcfce7;
      color: #166534;
    }

    .freq-score {
      background-color: #fce7f3;
      color: #9d174d;
    }

    .no-results {
      text-align: center;
      padding: 40px 20px;
      color: #94a3b8;
    }

    .no-results i {
      font-size: 40px;
      margin-bottom: 15px;
      color: #cbd5e1;
    }

    .result-stats {
      padding: 12px 16px;
      background-color: #f1f5f9;
      border-radius: 10px;
      font-size: 13px;
      color: #475569;
      margin-top: 10px;
      display: flex;
      justify-content: space-between;
      flex-wrap: wrap;
      gap: 8px;
    }

    .search-strategy {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-bottom: 10px;
    }

    .search-strategy label {
      font-weight: 500;
      color: #334155;
    }

    .search-strategy select {
      padding: 6px 12px;
      border-radius: 6px;
      border: 1px solid #cbd5e1;
      background-color: white;
      font-size: 14px;
    }

    .markdown-content {
      line-height: 1.7;
    }

    .markdown-content h1,
    .markdown-content h2,
    .markdown-content h3 {
      margin: 12px 0 8px;
      color: #1e293b;
    }

    .markdown-content p {
      margin-bottom: 12px;
    }

    .markdown-content ul,
    .markdown-content ol {
      padding-left: 22px;
      margin-bottom: 12px;
    }

    .markdown-content li {
      margin-bottom: 6px;
    }

    .markdown-content pre {
      background-color: #1e293b;
      color: #f8fafc;
      padding: 12px;
      border-radius: 8px;
      overflow-x: auto;
      margin: 12px 0;
      font-size: 14px;
    }

    .markdown-content code {
      background-color: #e2e8f0;
      padding: 2px 5px;
      border-radius: 4px;
      font-size: 14px;
    }

    .markdown-content blockquote {
      border-left: 4px solid #3b82f6;
      padding-left: 12px;
      margin: 12px 0;
      color: #475569;
    }

    /* 响应式设计 */
    @media (max-width: 768px) {
      .container {
        flex-direction: column;
      }

      .results-section {
        width: 100%;
        height: 40vh;
        border-top: 1px solid #e2e8f0;
        border-left: none;
      }

      .message {
        max-width: 90%;
      }

      .input-wrapper input {
        padding: 10px 14px;
        font-size: 15px;
      }

      .input-wrapper button {
        width: 42px;
        height: 42px;
      }
    }

    /* 滚动条样式 */
    .chat-container::-webkit-scrollbar,
    .results-container::-webkit-scrollbar {
      width: 6px;
    }

    .chat-container::-webkit-scrollbar-track,
    .results-container::-webkit-scrollbar-track {
      background: #f1f5f9;
      border-radius: 4px;
    }

    .chat-container::-webkit-scrollbar-thumb,
    .results-container::-webkit-scrollbar-thumb {
      background: #cbd5e1;
      border-radius: 4px;
    }

    .chat-container::-webkit-scrollbar-thumb:hover,
    .results-container::-webkit-scrollbar-thumb:hover {
      background: #94a3b8;
    }
  </style>
</head>

<body>
  <div class="container">
    <!-- 左侧聊天区域 -->
    <div class="chat-section">
      <div class="chat-header">
        <h2>智能问答系统</h2>
        <div class="chat-header-info">
          <i class="fa fa-database"></i> 基于数据库检索
        </div>
      </div>

      <div class="chat-container" id="chat-container">
        <div class="message bot-message">
          <div class="markdown-content">
            <p>您好！我是智能问答助手，我可以根据数据库中的知识回答您的问题。</p>
            <p>请随时向我提问，我会尽力提供准确、详细的回答。</p>
          </div>
          <div class="source-info">
            <i class="fa fa-info-circle"></i> 回答基于数据库中的专业知识
          </div>
        </div>
      </div>

      <div class="input-container">
        <div class="search-strategy">
          <label for="search-strategy">检索策略:</label>
          <select id="search-strategy">
            <option value="hybrid_search">混合检索</option>
            <option value="tfidf_expansion_vector_search">TF-IDF扩展向量检索</option>
            <option value="improved_keyword_search">改进的关键词检索</option>
          </select>
        </div>

        <div class="input-wrapper">
          <input type="text" id="user-input" placeholder="请输入您的问题..." autocomplete="off">
          <button id="send-btn">
            <i class="fa fa-paper-plane"></i>
          </button>
        </div>
      </div>
    </div>

    <!-- 右侧检索结果区域 -->
    <div class="results-section">
      <div class="results-header">
        <h2><i class="fa fa-search"></i> 检索结果详情</h2>
      </div>
      <div class="results-container" id="results-container">
        <div class="no-results">
          <i class="fa fa-file-text-o"></i>
          <p>检索结果将在此处显示</p>
          <p class="result-stats">提交问题后，系统会展示数据库检索详情</p>
        </div>
      </div>
    </div>
  </div>

  <script>
    // 后端API地址
    const API_URL = "http://localhost:5000/api/ask";
    let articleTitle = null; // 存储文章标题

    // DOM元素
    const chatContainer = document.getElementById('chat-container');
    const resultsContainer = document.getElementById('results-container');
    const userInput = document.getElementById('user-input');
    const sendBtn = document.getElementById('send-btn');
    const searchStrategySelect = document.getElementById('search-strategy');

    // 添加消息到聊天容器
    function addMessage(content, isUser = false) {
      const messageDiv = document.createElement('div');
      messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;

      // 用户消息
      if (isUser) {
        messageDiv.textContent = content;
      }
      // AI消息
      else {
        messageDiv.innerHTML = `
          <div class="markdown-content">${formatMarkdown(content)}</div>
          <div class="source-info">
            <i class="fa fa-database"></i> 基于数据库检索结果生成
          </div>
        `;
      }

      chatContainer.appendChild(messageDiv);
      chatContainer.scrollTop = chatContainer.scrollHeight;
    }

    // 显示正在输入状态
    function showTypingIndicator() {
      const typingDiv = document.createElement('div');
      typingDiv.className = 'message bot-message';
      typingDiv.id = 'typing-indicator';
      typingDiv.innerHTML = `
        <div class="typing-indicator">
          <div class="typing-dot"></div>
          <div class="typing-dot"></div>
          <div class="typing-dot"></div>
          正在检索数据库并生成回答...
        </div>
      `;
      chatContainer.appendChild(typingDiv);
      chatContainer.scrollTop = chatContainer.scrollHeight;
    }

    // 隐藏正在输入状态
    function hideTypingIndicator() {
      const typingIndicator = document.getElementById('typing-indicator');
      if (typingIndicator) {
        typingIndicator.remove();
      }
    }

    // 渲染检索结果
    function renderSearchResults(results, query, stats) {
      // 清空现有结果
      resultsContainer.innerHTML = '';

      // 添加统计信息
      const statsDiv = document.createElement('div');
      statsDiv.className = 'result-stats';
      statsDiv.innerHTML = `
        <div>查询: <strong>${query}</strong></div>
        <div>耗时: <strong>${stats.total_time.toFixed(3)}秒</strong></div>
        <div>文档: ${results.length}/${stats.total_docs}</div>
        ${articleTitle ? `<div>文章标题: <strong>${articleTitle}</strong></div>` : ''}
        <div>策略: <strong>${getStrategyName(searchStrategySelect.value)}</strong></div>
      `;
      resultsContainer.appendChild(statsDiv);

      // 如果没有结果
      if (results.length === 0) {
        const noResults = document.createElement('div');
        noResults.className = 'no-results';
        noResults.innerHTML = `
          <i class="fa fa-file-text-o"></i>
          <p>未找到相关文档</p>
          <p>请尝试调整查询关键词</p>
        `;
        resultsContainer.appendChild(noResults);
        return;
      }

      // 渲染每个结果
      results.forEach((result, index) => {
        const card = document.createElement('div');
        card.className = 'result-card';

        // 动态创建分数标签
        const scoresHtml = [];

        // BM25分数
        if (result.bm25_score !== undefined && result.bm25_score !== null) {
          scoresHtml.push(`<div class="score-badge bm25-score">BM25: ${result.bm25_score.toFixed(4)}</div>`);
        }

        // DPR分数
        if (result.dpr_score !== undefined && result.dpr_score !== null) {
          scoresHtml.push(`<div class="score-badge dpr-score">DPR: ${result.dpr_score.toFixed(4)}</div>`);
        }

        // 混合分数
        if (result.hybrid_score !== undefined && result.hybrid_score !== null) {
          scoresHtml.push(`<div class="score-badge hybrid-score">混合: ${result.hybrid_score.toFixed(4)}</div>`);
        }

        // 最终分数
        if (result.score !== undefined && result.score !== null) {
          scoresHtml.push(`<div class="score-badge final-score">最终: ${result.score.toFixed(4)}</div>`);
        }

        // 原始分数（仅适用于TF-IDF策略）
        if (result.original_score !== undefined && result.original_score !== null) {
          scoresHtml.push(`<div class="score-badge original-score">原始: ${result.original_score.toFixed(4)}</div>`);
        }

        // 位置权重（仅适用于关键词检索）
        if (result.position_weight !== undefined && result.position_weight !== null) {
          scoresHtml.push(`<div class="score-badge position-score">位置: ${result.position_weight.toFixed(2)}</div>`);
        }

        // 标题匹配（仅适用于关键词检索）
        if (result.title_match !== undefined && result.title_match !== null) {
          scoresHtml.push(`<div class="score-badge title-score">标题: ${result.title_match.toFixed(2)}</div>`);
        }

        // 词频增强（仅适用于关键词检索）
        if (result.term_freq_boost !== undefined && result.term_freq_boost !== null) {
          scoresHtml.push(`<div class="score-badge freq-score">词频: ${result.term_freq_boost.toFixed(2)}</div>`);
        }

        card.innerHTML = `
          <div class="result-title">
            <i class="fa fa-file-text-o"></i>
            ${index + 1}. ${result.title}
          </div>
          <div class="result-content">
            ${result.content}
          </div>
          <div class="result-scores">
            ${scoresHtml.join('')}
          </div>
        `;

        resultsContainer.appendChild(card);
      });

      // 滚动到顶部
      resultsContainer.scrollTop = 0;
    }

    // 获取策略名称
    function getStrategyName(strategy) {
      switch(strategy) {
        case 'hybrid_search': return '混合检索';
        case 'tfidf_expansion_vector_search': return 'TF-IDF扩展向量检索';
        case 'improved_keyword_search': return '改进的关键词检索';
        default: return strategy;
      }
    }

    // 格式化Markdown内容为HTML
    function formatMarkdown(text) {
      // 简单实现Markdown转换
      let html = text
        .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') // 加粗
        .replace(/\*(.*?)\*/g, '<em>$1</em>') // 斜体
        .replace(/```([\s\S]*?)```/g, '<pre>$1</pre>') // 代码块
        .replace(/`(.*?)`/g, '<code>$1</code>') // 行内代码
        .replace(/^# (.*$)/gm, '<h3>$1</h3>') // 标题
        .replace(/^- (.*$)/gm, '<li>$1</li>') // 无序列表
        .replace(/^\d+\. (.*$)/gm, '<li>$1</li>') // 有序列表
        .replace(/(<li>.*<\/li>)/gs, '<ul>$1</ul>') // 包裹列表
        .replace(/> (.*$)/gm, '<blockquote>$1</blockquote>') // 引用
        .replace(/\n/g, '<br>'); // 换行

      return html;
    }

    // 发送消息到后端
    async function sendMessage() {
      const query = userInput.value.trim();
      if (!query) return;

      // 检查是否已输入标题
      if (!articleTitle) {
        addMessage("请先输入文章标题", true);
        addMessage("您尚未输入文章标题，请先提供标题以便准确检索相关内容。", false);
        return;
      }

      // 获取用户选择的检索策略
      const searchStrategy = searchStrategySelect.value;

      // 禁用输入和按钮
      userInput.value = '';
      userInput.disabled = true;
      sendBtn.disabled = true;

      // 添加用户消息
      addMessage(query, true);

      // 显示正在输入状态
      showTypingIndicator();

      try {
        // 发送请求到后端，包含文章标题
        const response = await fetch(API_URL, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            query: query,
            search_strategy: searchStrategy,
            article_title: articleTitle // 添加文章标题到请求参数
          })
        });

        if (!response.ok) {
          throw new Error(`请求失败: ${response.status}`);
        }

        const data = await response.json();

        // 隐藏正在输入状态
        hideTypingIndicator();

        // 添加AI回复
        addMessage(data.model_answer);

        // 渲染检索结果
        renderSearchResults(data.search_results, data.query, data.stats);

      } catch (error) {
        console.error('请求错误:', error);
        hideTypingIndicator();
        addMessage(`抱歉，处理您的请求时出错: ${error.message}`);

        // 显示错误状态
        resultsContainer.innerHTML = `
          <div class="no-results">
            <i class="fa fa-exclamation-triangle"></i>
            <p>检索结果加载失败</p>
            <p>${error.message}</p>
          </div>
        `;
      } finally {
        // 重新启用输入
        userInput.disabled = false;
        sendBtn.disabled = false;
        userInput.focus();
      }
    }

    // 事件监听
    sendBtn.addEventListener('click', sendMessage);

    userInput.addEventListener('keypress', (e) => {
      if (e.key === 'Enter') {
        sendBtn.click();
      }
    });

    // 页面加载完成后请求文章标题
    window.addEventListener('DOMContentLoaded', () => {
      // 聚焦输入框
      userInput.focus();

      // 弹出对话框让用户输入文章标题
      requestArticleTitle();
    });

    // 请求文章标题的函数
    function requestArticleTitle() {
      // 使用prompt获取文章标题
      const title = prompt("请输入文章标题，以便系统更好地为您提供相关信息:", "");

      if (title === null || title.trim() === "") {
        // 用户取消或输入为空，显示提示并重新请求
        addMessage("您尚未输入文章标题，请提供标题以便继续使用系统。", false);
        // 延迟一段时间后再次请求，避免连续弹出
        setTimeout(requestArticleTitle, 1000);
      } else {
        // 保存文章标题
        articleTitle = title.trim();
        addMessage(`已记录文章标题: ${articleTitle}`, false);
      }
    }
  </script>
</body>
</html>